﻿#ifndef __INC_QG_OGL_CNV_H__
#define __INC_QG_OGL_CNV_H__

#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4624)
#endif

#include "qg_es2_dev.h"

namespace ES2Convert
{
	// color format
	inline GLint DetectColorFormat(qgColorFormat fmt, GLenum& pxfmt, GLenum& pxtype, bool& alpha)
	{
		// pxfmt = 색깔 포맷
		// pxtype = 색깔 데이터 타입
		// 반환값 = 실제 포맷 (ES2에서는 pxfmt와 같아야함)
		switch (K_CAST_ENUM(fmt))
		{
			case QGCF8_L:
				alpha = false;
				pxtype = GL_UNSIGNED_BYTE;
				return pxfmt = GL_LUMINANCE;

			case QGCF16_L:
				alpha = false;
				pxtype = GL_UNSIGNED_SHORT;
				return pxfmt = GL_LUMINANCE;

			case QGCF16_RGB:
				alpha = false;
				pxtype = GL_UNSIGNED_SHORT_5_6_5;
				return pxfmt = GL_RGB;	// GL_RGB565;

			case QGCF16_RGBA:
				alpha = true;
#if FALSE
				pxtype = GL_UNSIGNED_SHORT_4_4_4_4;
				return pxfmt = GL_RGBA;	// GL_RGBA4;
#else
				pxtype = GL_UNSIGNED_SHORT_5_5_5_1;
				return pxfmt = GL_RGBA; // GL_RGB5_A1;
#endif

			case QGCF32_RGB:	// BGR가 없어서 대체, 24비트일 수 있음
				alpha = false;
				pxtype = GL_UNSIGNED_BYTE;
				//return pxfmt = _es2::TestCapsExt(ES2Device::EI_OES_RGB8_RGBA8) ? GL_RGB8_OES : GL_RGB; 
				return pxfmt = GL_RGB;

			case QGCF32_RGBA:	// BGRA가 없어서 대체
				alpha = true;
				pxtype = GL_UNSIGNED_BYTE;
				//return pxfmt = _es2::TestCapsExt(ES2Device::EI_OES_RGB8_RGBA8) ? GL_RGBA8_OES : GL_RGBA;
				return pxfmt = GL_RGBA;	// GL_BGRA_EXT가 있음! GL_BGR이 없기 때문에 포기

			case QGCF32_BGR:
				alpha = false;
				pxtype = GL_UNSIGNED_BYTE;
				return pxfmt = GL_RGB;

			case QGCF32_BGRA:
				alpha = true;
				pxtype = GL_UNSIGNED_BYTE;
				return pxfmt = GL_RGBA;

			case QGCF16F_R:
				if (_es2::TestCapsExt(ES2Device::EI_OES_TEXTURE_HALF_FLOAT) &&
					_es2::TestCapsExt(ES2Device::EI_EXT_TEXTURE_STORAGE))
				{
					alpha = false;
					pxtype = GL_HALF_FLOAT_OES;
					return pxfmt = GL_LUMINANCE16F_EXT;	// 오류
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			case QGCF64F_BGRA:
				if (_es2::TestCapsExt(ES2Device::EI_OES_TEXTURE_HALF_FLOAT) &&
					_es2::TestCapsExt(ES2Device::EI_EXT_COLOR_BUFFER_HALF_FLOAT))
				{
					alpha = true;
					pxtype = GL_HALF_FLOAT_OES;
					return pxfmt = GL_RGBA16F_EXT;	// 오류
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			case QGCF32F_R:
				if (_es2::TestCapsExt(ES2Device::EI_OES_TEXTURE_HALF_FLOAT) &&
					_es2::TestCapsExt(ES2Device::EI_EXT_TEXTURE_STORAGE))
				{
					alpha = false;
					pxtype = GL_FLOAT;
					return pxfmt = GL_LUMINANCE32F_EXT;	// 오류
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			case QGCF128F_BGRA:
				if (_es2::TestCapsExt(ES2Device::EI_OES_TEXTURE_HALF_FLOAT) &&
					_es2::TestCapsExt(ES2Device::EI_EXT_TEXTURE_STORAGE))
				{
					alpha = true;
					pxtype = GL_FLOAT;
					return pxfmt = GL_RGBA32F_EXT;	// 오류
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			case QGCF_DXT1:
				if (_es2::TestCapsExt(ES2Device::EI_EXT_TEXTURE_COMPRESSION_DXT1))
				{
					alpha = true;
					pxtype = GL_NONE;
					return pxfmt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			case QGCF_DXT3:
				if (_es2::TestCapsExt(ES2Device::EI_ANGLE_TEXTURE_COMPRESSION_DXT3))
				{
					alpha = true;
					pxtype = GL_NONE;
					return pxfmt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + 1;	// GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			case QGCF_DXT5:
				if (_es2::TestCapsExt(ES2Device::EI_ANGLE_TEXTURE_COMPRESSION_DXT5))
				{
					alpha = true;
					pxtype = GL_NONE;
					return pxfmt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + 2;	// GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE
				}
				else
				{
					alpha = false;
					pxtype = GL_NONE;
					return pxfmt = GL_NONE;
				}

			default:
				alpha = false;
				pxtype = GL_NONE;
				return pxfmt = GL_NONE;
		}
	}

	//
	inline qgColorFormat ConvertColorFormat(GLenum fmt, GLenum pxtype)
	{
		// QGCF32_BGR, QGCF32_BGRA는 없음
		switch (K_CAST_ENUM(fmt))
		{
			case GL_LUMINANCE:
				return pxtype == GL_UNSIGNED_BYTE ? QGCF8_L : QGCF16_L;

			case GL_RGB565:
				return QGCF16_RGB;

			case GL_RGBA4:
			case GL_RGB5_A1:
				return QGCF16_RGBA;

			case GL_RGB8_OES:
			case GL_RGB:
				return QGCF32_RGB;
				
			case GL_RGBA8_OES:
			case GL_RGBA:
				return QGCF32_RGBA;

			case GL_LUMINANCE16F_EXT:
				return QGCF16F_R;

			case GL_RGBA16F_EXT:
				return QGCF64F_BGRA;

			case GL_LUMINANCE32F_EXT:
				return QGCF32F_R;

			case GL_RGBA32F_EXT:
				return QGCF128F_BGRA;
				
			case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
			case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
				return QGCF_DXT1;

			case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + 1:
				return QGCF_DXT3;

			case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + 2:
				return QGCF_DXT3;

			default:
				return QGCF_NONE;
		}
	}

	//
	inline bool TestLockableFormat(qgColorFormat fmt, GLenum& pxfmt, GLenum& pxtype)
	{
		switch (K_CAST_ENUM(fmt))
		{
			case QGCF8_L:
				pxfmt = GL_LUMINANCE;
				pxtype = GL_UNSIGNED_BYTE;
				return true;

			case QGCF16_L:
				pxfmt = GL_LUMINANCE;
				pxtype = GL_UNSIGNED_SHORT;
				return true;

			case QGCF16_RGB:
				pxfmt = GL_RGB;
				pxtype = GL_UNSIGNED_SHORT_5_6_5;
				return true;

			case QGCF16_RGBA:
				pxfmt = GL_RGBA;
#if 0
				pxtype = GL_UNSIGNED_SHORT_4_4_4_4;
#else
				pxtype = GL_UNSIGNED_SHORT_5_5_5_1;
#endif
				return true;

			case QGCF32_RGB:	// 24비트 일 수 있음
				pxfmt = GL_RGB;
				pxtype = GL_UNSIGNED_BYTE;
				return true;

			case QGCF32_RGBA:
				pxfmt = GL_RGBA;
				pxtype = GL_UNSIGNED_BYTE;
				return true;

			case QGCF32_BGR:	// BGR없음
				pxfmt = GL_RGB;
				pxtype = GL_UNSIGNED_BYTE;
				return true;

			case QGCF32_BGRA:	// BGR없음
				pxfmt = GL_RGBA;
				pxtype = GL_UNSIGNED_BYTE;
				return true;
		}

		return false;
	}

	//
	inline GLenum Topology(qgTopology tpg)
	{
		switch (K_CAST_ENUM(tpg))
		{
			case QGTPG_POINT_LIST:
				return GL_POINTS;

			case QGTPG_LINE_LIST:
				return GL_LINES;

			case QGTPG_LINE_STRIP:
				return GL_LINE_STRIP;

			case QGTPG_TRI_LIST:
				return GL_TRIANGLES;

			case QGTPG_TRI_STRIP:
				return GL_TRIANGLE_STRIP;
		}

		return GL_ZERO;
	}

	//
	inline GLint ComparisonOp(qgCmpOp cop)
	{
		switch (K_CAST_ENUM(cop))
		{
			case QGCOP_NEVER:
				return GL_NEVER;

			case QGCOP_LE:
				return GL_LESS;

			case QGCOP_EQ:
				return GL_EQUAL;

			case QGCOP_LEQ:
				return GL_LEQUAL;

			case QGCOP_GR:
				return GL_GREATER;

			case QGCOP_NEQ:
				return GL_NOTEQUAL;

			case QGCOP_GEQ:
				return GL_GEQUAL;

			case QGCOP_ALWAYS:
				return GL_ALWAYS;
		}

		return 0;
	}

	//
	inline GLenum BlendOp(qgBlendOp op)
	{
		switch (K_CAST_ENUM(op))
		{
			case QGBLO_ADD:
				return GL_FUNC_ADD;

			case QGBLO_SUB:
				return GL_FUNC_SUBTRACT;

			case QGBLO_RSUB:
				return GL_FUNC_REVERSE_SUBTRACT;

			case QGBLO_MIN:
			case QGBLO_FMIN:
#ifdef GL_MIN
				return GL_MIN;
#elif defined(GL_MIN_EXT)
				return GL_MIN_EXT;
#else
				return GL_FUNC_ADD;
#endif

			case QGBLO_MAX:
			case QGBLO_FMAX:
#ifdef GL_MAX
				return GL_MAX;
#elif defined(GL_MIN_EXT)
				return GL_MAX_EXT;
#else
				return GL_FUNC_ADD;
#endif
		}

		return 0;
	}

	//
	inline GLenum BlendValue(qgBlendValue v)
	{
		switch (K_CAST_ENUM(v))
		{
			case QGBLV_ZERO:
				return GL_ZERO;

			case QGBLV_ONE:
				return GL_ONE;

			case QGBLV_SC:
				return GL_SRC_COLOR;

			case QGBLV_SC_INV:
				return GL_ONE_MINUS_SRC_COLOR;

			case QGBLV_SA:
				return GL_SRC_ALPHA;

			case QGBLV_SA_INV:
				return GL_ONE_MINUS_SRC_ALPHA;

			case QGBLV_DA:
				return GL_DST_ALPHA;

			case QGBLV_DA_INV:
				return GL_ONE_MINUS_DST_ALPHA;

			case QGBLV_DC:
				return GL_DST_COLOR;

			case QGBLV_DC_INV:
				return GL_ONE_MINUS_DST_COLOR;

			case QGBLV_SAS:
				return GL_SRC_ALPHA_SATURATE;
		}

		return 0;
	}

	//
	inline bool Filter(qgFilter v, bool ismip, GLint* mag, GLint* min)
	{
		switch (K_CAST_ENUM(v))
		{
			case QGFLT_MAG_MIN_MIP_POINT:
				*mag = GL_NEAREST;
				*min = ismip ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
				break;

			case QGFLT_MAG_MIN_POINT_MIP_LINEAR:
				*mag = GL_NEAREST;
				*min = ismip ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
				break;

			case QGFLT_MAG_POINT_MIN_LINEAR_MIP_POINT:
				*mag = GL_NEAREST;
				*min = ismip ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR;
				break;

			case QGFLT_MAG_POINT_MIN_MIP_LINEAR:
				*mag = GL_NEAREST;
				*min = ismip ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
				break;

			case QGFLT_MAG_LINEAR_MIN_MIP_POINT:
				*mag = GL_LINEAR;
				*min = ismip ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
				break;

			case QGFLT_MAG_LINEAR_MIN_POINT_MIP_LINEAR:
				*mag = GL_LINEAR;
				*min = ismip ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
				break;

			case QGFLT_MAG_MIN_LINEAR_MIP_POINT:
				*mag = GL_LINEAR;
				*min = ismip ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR;
				break;

			case QGFLT_MAG_MIN_MIP_LINEAR:
				*mag = GL_LINEAR;
				*min = ismip ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
				break;

			case QGFLT_ANISOTROPIC:
				*mag = GL_LINEAR;
				*min = ismip ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
				return FALSE;

			case QGFLTX_LINEAR:
				*mag = GL_LINEAR;
				*min = GL_LINEAR;
				return FALSE;

			case QGFLTX_POINT:		// 포인트가 없다 NEAREST로
			default:
				*mag = GL_NEAREST;
				*min = GL_NEAREST;
				return FALSE;
		}

		return TRUE;
	}

	//
	inline GLint Address(qgAddress v)
	{
		switch (K_CAST_ENUM(v))
		{
			case QGADR_WRAP:
				return GL_REPEAT;

			case QGADR_MIRROR:
				return GL_MIRRORED_REPEAT;

			case QGADR_CLAMP:
				return GL_CLAMP_TO_EDGE;

			case QGADR_BORDER:
				return GL_CLAMP_TO_EDGE;

			default:
				return GL_REPEAT;
		}
	}

	// 
	inline GLenum ShaderType(qgShaderType type)
	{
		switch (K_CAST_ENUM(type))
		{
			case QGSHADER_PS:
				return GL_FRAGMENT_SHADER;

			case QGSHADER_VS:
				return GL_VERTEX_SHADER;

			default:
				return 0;
		}
	}

	//
	inline GLenum TextureType(qgTextureType type)
	{
		switch (K_CAST_ENUM(type))
		{
			case QGTEXTURE_1D:	// 지원안함 2D 1DIM으로 사용할 것
				return GL_TEXTURE_2D;

			case QGTEXTURE_2D:
				return GL_TEXTURE_2D;

			case QGTEXTURE_CUBE:
				return GL_TEXTURE_CUBE_MAP;

			case QGTEXTURE_3D:	// 지원안함. ES3에서는 지원함
				return 0;

			default:
				return 0;
		}
	}

	//
	inline GLenum DepthComponent(kint zbpp)
	{
#if 0
		switch (zbpp)
		{
			case 16:
				return GL_DEPTH_COMPONENT16;

			case 24:	// 지원안함
			case 32:	// 지원안함
			default:
				return GL_DEPTH_COMPONENT;
		}
#else
		return GL_DEPTH_COMPONENT;
#endif
	}
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif	// __INC_QG_OGL_CNV_H__
